package com.zzjr.tools.java.ssm.factory;

import com.zzjr.tools.java.ssm.constants.AutoCodeConstants;
import com.zzjr.tools.java.ssm.utils.CamelUtils;
import com.zzjr.tools.java.ssm.utils.DBUtils;
import com.zzjr.tools.java.ssm.utils.IOUtils;
import com.zzjr.tools.java.ssm.utils.StringUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Description: 用于生成Mybatis配置文件的工厂类
 * 
 * @Date Create on 2015年10月13日
 * @author <a href="mailto:Aromarich@zuozh.com">Aromarich</a>
 * @since version1.0 Copyright 2015 ZZJR All Rights Reserved.
 */
public class MapperFactoryBackUp {
	
	static private String tableName;
	
	static private String[] colnames;
	
	static private String[] colTypes;
	
	// Mapper实体类文件路径
	static private File mapperFile;
	
	// java Model对象名
	static private String modelName;
	
	/**
	 * 创建实体类Mybatis配置文件
	 */
	public static void generateMapperXml(String tbName) {
		System.out.println("开始生成实体类Mybatis配置文件");
		
		tableName = tbName;
		modelName = StringUtils.upperFirstChar(CamelUtils.convertUnderLineToCamel(tableName));
		
		// 1.创建xml包
		String mapperDir = AutoCodeConstants.PACKAGE_FULL_PATH + File.separator + "xml";
		IOUtils.mkDir(new File(mapperDir));
		
		// 2.创建文件
		String filePath = mapperDir + File.separator + tableName + ".xml";
		mapperFile = new File(filePath);
		IOUtils.createNewFile(mapperFile);
		
		// 3.往Mybatis配置文件中写入内容
		writeToMapperFile();
		
		System.out.println("完成实体类Mybatis配置文件的生成");
	}
	
	/**
	 * 
	 */
	private static void writeToMapperFile() {
		// 1根据表名获取字段属性
		colnames = DBUtils.getColumnNameByTableName(tableName);
		colTypes = DBUtils.getColumnTypeByTableName(tableName);
		
		// 2.生成Mapper
		StringBuilder content = parseMapperFile();
		FileWriter fw;
		PrintWriter pw;
		try {
			fw = new FileWriter(mapperFile);
			pw = new PrintWriter(fw);
			pw.println(content.toString());
			pw.flush();
			pw.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建Mybatis配置文件
	 * 
	 * @return
	 */
	private static StringBuilder parseMapperFile() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
		sb.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\r\n");
		sb.append("<!--").append(modelName).append("的映射-->\r\n");
		sb.append("<mapper namespace=\"" + modelName + "\">\r\n");
		
		// 处理resultMap
		processResultMap(sb);
		
		// 处理公共抽象模块
		processCommonPart(sb);
		
		// 处理方法
		processMethod(sb);
		
		sb.append("</mapper>\r\n");
		return sb;
	}
	
	/**
	 * 处理resultMap
	 * 
	 * @param sb
	 */
	private static void processResultMap(StringBuilder sb) {
		sb.append("\t<resultMap id=\"" + modelName + "Map\" type=\"" + modelName + "\">\r\n");
		sb.append("\t\t<id column=\"id\" property=\"id\" jdbcType=\"INTEGER\" />\r\n");
		for (int i = 1; i < colnames.length; i++) {
			sb.append("\t\t<result column=\"" + colnames[i] + "\" property=\""
					+ CamelUtils.convertUnderLineToCamel(colnames[i]) + "\" jdbcType=\""
					+ sqlType2JdbcType(colTypes[i]) + "\" />\r\n");
		}
		sb.append("\t</resultMap>\r\n\r\n");
	}
	
	/**
	 * 处理公共抽象模块
	 * 
	 * @param sb
	 */
	private static void processCommonPart(StringBuilder sb) {
		// 1.抽取表名
		sb.append("\t<!-- 抽取表名 -->\r\n");
		sb.append("\t<sql id=\"tableName\">\r\n");
		sb.append("\t\t" + tableName + "\r\n");
		sb.append("\t</sql>\r\n\r\n");
		
		// 2.抽取公共表字段
		sb.append("\t<!--抽取公共表字段 -->\r\n");
		sb.append("\t<sql id=\"columns\">\r\n");
		for (int i = 0; i < colnames.length; i++) {
			sb.append("\t\t" + colnames[i].toUpperCase());
			if (i != colnames.length - 1) {
				sb.append(",");
			}
			sb.append("\r\n");
		}
		sb.append("\t</sql>\r\n\r\n");
		
		// 3.抽取公共实体类属性
		sb.append("\t<!-- 抽取公共实体类属性 -->\r\n");
		sb.append("\t<sql id=\"javaProps\">\r\n");
		for (int i = 0; i < colnames.length; i++) {
			sb.append("\t\t#{" + CamelUtils.convertUnderLineToCamel(colnames[i]) + ",jdbcType="
					+ sqlType2JdbcType(colTypes[i]) + "}");
			if (i != colnames.length - 1) {
				sb.append(",");
			}
			sb.append("\r\n");
		}
		sb.append("\t</sql>\r\n\r\n");
		
		// 4.抽取condition
		sb.append("\t<!-- 条件 -->\r\n");
		sb.append("\t<sql id=\"condition\">\r\n");
		for (int i = 1; i < colnames.length; i++) {
			sb.append("\t\t<if test=\"" + CamelUtils.convertUnderLineToCamel(colnames[i]) + "!= null\">\r\n");
			sb.append("\t\t\t" + colnames[i].toUpperCase() + " = #{" + CamelUtils.convertUnderLineToCamel(colnames[i])
					+ ",jdbcType=" + sqlType2JdbcType(colTypes[i]) + "},\r\n");
			sb.append("\t\t</if>\r\n");
		}
		sb.append("\t</sql>\r\n\r\n");
	}
	
	/**
	 * 处理方法: 默认有insertXxx,deleteXxxById,updateXxxById,selectXxxById,selectAll
	 * 5个通用方法
	 * 
	 * @param sb
	 */
	private static void processMethod(StringBuilder sb) {
		sb.append("\t\r\n");
		// 1.生成insertXxx
		sb.append("\t<!-- 插入 -->\r\n");
		sb.append("\t<insert id=\"insert" + modelName + "\" parameterType=\"" + modelName
				+ "\" useGeneratedKeys=\"true\" keyProperty=\"id\">\r\n");
		sb.append("\t\tINSERT INTO\r\n");
		sb.append("\t\t\t<include refid=\"tableName\" />\r\n");
		sb.append("\t\t(\r\n");
		sb.append("\t\t\t<include refid=\"columns\" />\r\n");
		sb.append("\t\t)\r\n");
		sb.append("\t\tVALUES\r\n");
		sb.append("\t\t(\r\n");
		sb.append("\t\t\t<include refid=\"javaProps\" />\r\n");
		sb.append("\t\t)\r\n");
		sb.append("\t</insert>\r\n\r\n");
		
		// 2.生成deleteXxxById
		sb.append("\t<!-- 根据id删除 -->\r\n");
		sb.append("\t<delete id=\"delete" + modelName + "ById\" parameterType=\"java.lang.Long\">\r\n");
		sb.append("\t\tDELETE FROM\r\n");
		sb.append("\t\t\t<include refid=\"tableName\" />\r\n");
		sb.append("\t\tWHERE\r\n");
		sb.append("\t\t\tID = #{id,jdbcType=INTEGER}\r\n");
		sb.append("\t\tLIMIT 1\r\n");
		sb.append("\t</delete>\r\n\r\n");
		
		// 3.生成updateXxxById
		sb.append("\t<!-- 根据id更新信息 -->\r\n");
		sb.append("\t<update id=\"update" + modelName + "ById\" parameterType=\"java.lang.Integer\">\r\n");
		sb.append("\t\tUPDATE\r\n");
		sb.append("\t\t\t<include refid=\"tableName\" />\r\n");
		sb.append("\t\t<set>\r\n");
		sb.append("\t\t\t<include refid=\"condition\" />\r\n");
		sb.append("\t\t</set>\r\n");
		sb.append("\t\tWHERE\r\n");
		sb.append("\t\t\tID = #{id,jdbcType=INTEGER}\r\n");
		sb.append("\t\tLIMIT 1\r\n");
		sb.append("\t</update>\r\n\r\n");
		
		// 4.生成selectXxxById
		sb.append("\t<!-- 根据id查找对应的信息 -->\r\n");
		sb.append("\t<select id=\"select" + modelName + "ById\" resultMap=\"" + modelName
				+ "Map\" parameterType=\"java.lang.Long\">\r\n");
		sb.append("\t\tSELECT\r\n");
		sb.append("\t\t\t<include refid=\"columns\" />\r\n");
		sb.append("\t\tFROM\r\n");
		sb.append("\t\t\t<include refid=\"tableName\" />\r\n");
		sb.append("\t\tWHERE\r\n");
		sb.append("\t\t\tID = #{id,jdbcType=INTEGER}\r\n");
		sb.append("\t\tLIMIT 1\r\n");
		sb.append("\t</select>\r\n\r\n");
		
		// 5.生成selectAll
		sb.append("\t<!-- 查找所有信息 -->\r\n");
		sb.append("\t<select id=\"selectAll" + modelName + "\" resultMap=\"" + modelName + "Map\">\r\n");
		sb.append("\t\tSELECT\r\n");
		sb.append("\t\t\t<include refid=\"columns\" />\r\n");
		sb.append("\t\tFROM\r\n");
		sb.append("\t\t\t<include refid=\"tableName\" />\r\n");
		sb.append("\t</select>\r\n\r\n");
	}
	
	/**
	 * 功能：获得列的数据类型
	 * 
	 * @param sqlType
	 * @return
	 */
	private static String sqlType2JdbcType(String sqlType) {
		
		if (sqlType.equalsIgnoreCase("int")) {
			return "INTEGER";
		} else if (sqlType.equalsIgnoreCase("tinyint")) {
			return "INTEGER";
		} else if (sqlType.equalsIgnoreCase("bigint")) {
			return "BIGINT";
		} else if (sqlType.equalsIgnoreCase("float")) {
			return "FLOAT";
		} else if (sqlType.equalsIgnoreCase("double")) {
			return "DOUBLE";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "BLOB";
		} else if (sqlType.equalsIgnoreCase("char") || sqlType.equalsIgnoreCase("varchar")) {
			return "VARCHAR";
		} else if (sqlType.equalsIgnoreCase("date") || sqlType.equalsIgnoreCase("datetime")
				|| sqlType.equalsIgnoreCase("timestamp")) {
			return "TIMESTAMP";
		}
		
		return "VARCHAR";
	}
}
